﻿using Lights.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cudafy;
using Cudafy.Host;
using Cudafy.Translator;
using System.Threading;

namespace Lights.Processing
{
    public class Brightness : IModule
    {
        private CudafyModule module;

        public Brightness()
        {
            module = CudafyTranslator.Cudafy(eArchitecture.OpenCL);
        }

        [Cudafy]
        static void Compute(GThread thread, byte[] src, byte[] dst, int width, int height, float value)
        {
            int x = (thread.blockIdx.x * thread.blockDim.x + thread.threadIdx.x);
            int y = thread.blockIdx.y * thread.blockDim.y + thread.threadIdx.y;
            int i = (x + y * (thread.blockDim.x * thread.gridDim.x)) * 4;

            if (i >= width * height * 4)
                return;

            dst[i + 3] = src[i + 3];
            for (int j = i; j < (i + 3); j++)
            {
                dst[j] = (byte)GMath.Max(0, GMath.Min(255, src[j] + value));
            }

        }

        public void Execute(GPGPU gpu, byte[] src, byte[] dst, int width, int height, params object[] values)
        {
            float value = (float)values[0];

            if (gpu != null)
            {
                gpu.LoadModule(module);

                dim3 blockSize = new dim3(16, 16);
                dim3 gridSize = new dim3(width / blockSize.x + 1, height / blockSize.y + 1);

                gpu.Launch(gridSize, blockSize).Compute(src, dst, width, height, (float)values[0]);
            }
            else
            {
                int length = width * height;
                if (dst == null || dst.Length != src.Length)
                    throw new ArgumentNullException();

                Parallel.For(0, length, (i) =>
                {
                    int x = i * 4;
                    dst[x + 3] = src[x + 3];
                    for (int j = x; j < (x + 3); j++)
                    {
                        dst[j] = (byte)Math.Max(0, Math.Min(255, (src[j] + value)));
                    }
                });
            }
        }

        public string Name
        {
            get { return typeof(Brightness).Name; }
        }
    }
}
